#ifndef UTILS_H
#define UTILS_H

#include <cstdint>
#include <utility>//std::swap
#if defined(_MSC_VER) && (_MSC_VER>1600)
#pragma execution_character_set("utf-8")
#endif

namespace tool {

using Handler = void*;

inline constexpr const char* BoolStr(bool state){
    return state?"true":"false";
}

inline constexpr const char* StateStr(bool state){
    return state?"success":"failed";
}


template<typename T, uint32_t N>
inline constexpr uint32_t ArraySize(const T(&)[N])
{
    return N;
}

inline constexpr uint32_t MakeUInt32(uint16_t low, uint16_t high)
{
    return  uint32_t(low) | (uint32_t(high) << 16);
}

inline constexpr int32_t MakeInt32(uint16_t low, uint16_t high)
{
    return  static_cast<int32_t>(uint32_t(low) | (uint32_t(high) << 16));
}



template <typename T>
constexpr T ByteSwap(T source);


template <>
inline constexpr uint64_t ByteSwap<uint64_t>(uint64_t source)
{
    return 0
        | ((source & UINT64_C(0x00000000000000ff)) << 56)
        | ((source & UINT64_C(0x000000000000ff00)) << 40)
        | ((source & UINT64_C(0x0000000000ff0000)) << 24)
        | ((source & UINT64_C(0x00000000ff000000)) << 8)
        | ((source & UINT64_C(0x000000ff00000000)) >> 8)
        | ((source & UINT64_C(0x0000ff0000000000)) >> 24)
        | ((source & UINT64_C(0x00ff000000000000)) >> 40)
        | ((source & UINT64_C(0xff00000000000000)) >> 56);
}

template <>
inline constexpr uint32_t ByteSwap<uint32_t>(uint32_t source)
{
    return 0
        | ((source & 0x000000ff) << 24)
        | ((source & 0x0000ff00) << 8)
        | ((source & 0x00ff0000) >> 8)
        | ((source & 0xff000000) >> 24);
}

template <>
inline constexpr uint16_t ByteSwap<uint16_t>(uint16_t source)
{
    return uint16_t( 0
                    | ((source & 0x00ff) << 8)
                    | ((source & 0xff00) >> 8) );
}

template <>
inline constexpr uint8_t ByteSwap<uint8_t>(uint8_t source)
{
    return source;
}

// signed specializations
template <>
inline constexpr int64_t ByteSwap<int64_t>(int64_t source)
{
    return ByteSwap<uint64_t>(uint64_t(source));
}

template <>
inline constexpr int32_t ByteSwap<int32_t>(int32_t source)
{
    return ByteSwap<uint32_t>(uint32_t(source));
}

template <>
inline constexpr int16_t ByteSwap<int16_t>(int16_t source)
{
    return ByteSwap<uint16_t>(uint16_t(source));
}

template <>
inline constexpr int8_t ByteSwap<int8_t>(int8_t source)
{
    return source;
}

template <>
inline float ByteSwap<float>(float source)
{
    uint32_t value = ByteSwap(*reinterpret_cast<uint32_t*>(&source));
    return *reinterpret_cast<float*>(&value);
}

template <>
inline double ByteSwap<double>(double source)
{
    uint64_t value = ByteSwap(*reinterpret_cast<uint64_t*>(&source));
    return *reinterpret_cast<double*>(&value);
}

namespace detail{

union EndianHelper
{
    uint8_t c;
    uint16_t i;
};
}

inline constexpr bool IsLittleEndian()
{
    constexpr detail::EndianHelper u{0x00FF};
    return (u.c==0xFF);
}

template <typename T>
inline constexpr T ToBigEndian(T source)
{
    return IsLittleEndian()? ByteSwap(source):source;
}
template <typename T>
inline constexpr T FromBigEndian(T source)
{
    return IsLittleEndian() ? ByteSwap(source) : source;
}
template <typename T>
inline constexpr T ToLittleEndian(T source)
{
    return IsLittleEndian() ? source : ByteSwap(source);
}
template <typename T>
inline constexpr T FromLittleEndian(T source)
{
    return IsLittleEndian() ? source : ByteSwap(source);
}


inline constexpr uint32_t ToNetOrderL(uint32_t source)
{ return ToBigEndian(source); }

inline constexpr uint32_t FromNetOrderL(uint32_t source)
{ return FromBigEndian(source); }

inline constexpr uint16_t ToNetOrderS(uint16_t source)
{ return ToBigEndian(source); }

inline constexpr uint16_t FromNetOrderS(uint16_t source)
{ return FromBigEndian(source); }


}//namespace tool


#ifdef __GNUC__
#   define CHECK_FORMAT(str,arg) __attribute__((format(printf, str, arg)))
#else
#   define CHECK_FORMAT(str,arg)
#endif




#ifndef DISABLE_COPY
#define DISABLE_COPY(name) \
    name(const name&) = delete; \
    name& operator=(const name&) = delete;
#endif

#ifndef DEFAULT_MOVE
#define DEFAULT_MOVE(name) \
    name() noexcept:d(nullptr){} \
    name(name&& rhs) noexcept \
        :d(rhs.d){ rhs.d = nullptr; } \
    name& operator=(name&& rhs) noexcept \
    { std::swap(d,rhs.d);return *this; }\
    bool isNull() const\
    { return d == nullptr; }
#endif





#ifndef Q_D

template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(const Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); }

// The body must be a statement:
//#define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() \
    { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
    inline const Class##Private* d_func() const \
    { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
    friend class Class##Private;

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() \
    { return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr)); } \
    inline const Class##Private* d_func() const \
    { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr)); } \
    friend class Class##Private;

#define Q_DECLARE_PUBLIC(Class)                                    \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

#endif


#ifdef _WIN32
    #define DEBUGSOCK(name) fprintf(stderr,"SocketError<%s,%s,%d,(%s,%d)>:\n\tfunction[%s],code[%d]\n",__FILE__,__FUNCTION__,__LINE__,addr(),port(),name,WSAGetLastError())
    #define INIT_WIN_SOCK \
        WSADATA wsaData; \
        (void)WSAStartup(MAKEWORD(2, 2), &wsaData)
    #define CLEAN_WIN_SOCK \
        WSACleanup()
#else
    #define DEBUGSOCK(name) fprintf(stderr,"SocketError<%s,%s,%d,(%s,%d)>:\n\tfunction[%s],code[%d,%s]\n",__FILE__,__FUNCTION__,__LINE__,addr(),port(),name,errno,strerror(errno))
    #define INIT_WIN_SOCK
    #define CLEAN_WIN_SOCK
#endif

#define NETOPTSET(sock,level,optname,value)\
    if(setsockopt(sock,level,optname,reinterpret_cast<const char*>(&value),sizeof(value)) < 0){\
        DEBUGSOCK("setsockopt::"#optname);\
    }

#endif // UTILS_H
